﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Microsoft.HomeServer.Extensibility;
using Microsoft.HomeServer.SDK.Interop.v1;
using Umbrella.Whs.Logging;
using Umbrella.Whs.Contracts;

namespace Umbrella.Whs.WhsAddin
{
    public partial class UmbrellaSettingsTab : UserControl, ISettingsTab
    {
        internal delegate void OnSettingsCommittedDelegate(SettingsCache cache);

        public static readonly Guid SettingsTabGuid = new Guid("{E3B0A1D8-5EFF-49a4-83C3-4B86F850668B}");
        internal event OnSettingsCommittedDelegate OnSettingsCommitted;

        #region settings

        internal class SettingsCache
        {
            private readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(SettingsCache));
            private bool _loaded;

            public bool EnableErrorReporting
            {
                get;
                set;
            }

            public void LoadFromSettings()
            {
                try
                {
                    var s = Properties.Settings.Default;

                    // load singleton service settings
                    using (var ss = new SingletonServiceFactory())
                    {
                        if (ss.IsWindowsServiceRunning() == SingletonServiceFactory.ServiceStatus.Running)
                        {
                            var settings = ss.Channel.GetAllSettings();

                            this.EnableErrorReporting = settings.ErrorReportsSubmissionEnabled;
                        }
                    }
                }
                catch (Exception ex)
                {
                    _log.Fatal("Failed to load settings", ex);

                    throw;
                }
                finally
                {
                    _loaded = true;
                }
            }

            public void SaveToSettings(bool saveSettings)
            {
                // do not save if no settings have been loaded
                if (!_loaded)
                    return;

                try
                {
                    var s = Properties.Settings.Default;
	
                    if (saveSettings)
                    {
                        // save local settings
                        s.Save();
	
                        // save singleton service settings
                        using (var ss = new SingletonServiceFactory())
                        {
                            if (ss.IsWindowsServiceRunning() == SingletonServiceFactory.ServiceStatus.Running)
                            {
                                ss.Channel.SetAllSettings(new SettingsAll()
                                {
                                  ErrorReportsSubmissionEnabled = this.EnableErrorReporting,
                                });
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    _log.Fatal("Failed to save settings", ex);

                    throw;
                }
            }
        }

        #endregion

        private readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(UmbrellaSettingsTab));
        private readonly IConsoleServices _services;
        private readonly WHSInfoClass _whsInfo;
        private readonly SingletonServiceFactory _singletonService = new SingletonServiceFactory();
        private readonly SettingsCache _settings = new SettingsCache();

        public IConsoleServices Services
        {
            get { return _services; }
        }

        internal SettingsCache Settings
        {
            get { return _settings; }
        }

        static UmbrellaSettingsTab()
        {
            LogFactory.Configure("Addin");

            Xceed.FileSystem.Licenser.LicenseKey = Microsoft.HomeServer.Common.Licensing.XceedZipLibraryLicenseKey;
            Xceed.Zip.Licenser.LicenseKey = Microsoft.HomeServer.Common.Licensing.XceedZipLibraryLicenseKeyEx;
        }

        public UmbrellaSettingsTab(int width, int height, IConsoleServices consoleServices)
        {
            if (_log.IsDebugEnabled)
                _log.Debug("Initialization start");

            try
            {
                // preapre
                _services = consoleServices;
                _whsInfo = new WHSInfoClass();
                _whsInfo.Init(Umbrella.Whs.Properties.Constants.ApplicationName);
	
                this.Size = new Size(width, height);
	
                // create forms
                InitializeComponent();

                // update version text
                this.versionLabel.Text = ("v" + UmbrellaVersion.VersionString);

                // receive state transitions
                AddinStateManager.Instance.OnStateChanging += SetState;

                // done
                if (_log.IsDebugEnabled)
                    _log.Debug("Initialization done");
            }
            catch (Exception e)
            {
                _log.Fatal("Failed to initialize", e);

                throw;
            }
        }

        public bool Commit()
        {
            if (_log.IsDebugEnabled)
                _log.Debug("Committing settings...");

            try
            {
                _settings.SaveToSettings(true);

                // handle events
                if (this.OnSettingsCommitted != null)
                    OnSettingsCommitted(_settings);

                // reset main control tab
                /*
                var tt = (UmbrellaConsoleTab)_services.GetTab(UmbrellaConsoleTab.TabId);

                try
                {
                    tt.ResetState();
                }
                catch (Exception x)
                {
                    _log.Error("Failed to reset state on commit for " + tt.TabText + " (" + tt.TabIndex + ")", x);
                }*/
            }
            catch (Exception ex)
            {
                _log.Error("Failed to commit settings", ex);

                throw;
            }

            return true;
        }

        public bool GetHelp()
        {
            return false;
        }

        public Guid SettingsGuid
        {
            get { return SettingsTabGuid; }
        }

        public Control TabControl
        {
            get { return this; }
        }

        public Bitmap TabImage
        {
            get { return Properties.Resources.imgSettingsLogo; }
        }

        public string TabText
        {
            get { return Properties.Resources.txtSettingsTabTitle; }
        }

        private void UmbrellaSettingsTab_Load(object sender, EventArgs e)
        {
            if (_log.IsDebugEnabled)
                _log.Debug("Loading start");

            try
            {
                //_settings.LoadFromSettings();     // settings are being loaded on each state change

                ResetState();

                // select first tab as default
                this.tabSharePoint1.Select();

                // done
                if (_log.IsDebugEnabled)
                    _log.Debug("Loading done");
            }
            catch (Exception ex)
            {
                _log.Fatal("Loading failed", ex);

                throw;
            }
        }

        public void ResetState()
        {
            AddinStateManager.Instance.SetState(
                _singletonService.IsWindowsServiceRunning() == SingletonServiceFactory.ServiceStatus.Running ?
                AddinState.ConnectingToSharePoint :
                AddinState.WindowsServiceNotRunning
                );
        }

        private void SetState(object sender, AddinStateTransitionEventArgs args)
        {
            // log
            if (_log.IsDebugEnabled)
                _log.Debug("Changing state start: " + args.Previous + " to " + args.Next);

            // reload settings
            _settings.LoadFromSettings();

            // continue
            try
            {
                this.SuspendLayout();

                // cleanup
                CleanupFlowLayoutPanel(this.flowSharePoint);
                CleanupFlowLayoutPanel(this.flowFeatures);
                CleanupFlowLayoutPanel(this.flowMaintaince);
                CleanupFlowLayoutPanel(this.flowAbout);

                // change state
                InitializeState(args.Next);

                this.ResumeLayout();

                // log
                if (_log.IsDebugEnabled)
                    _log.Debug("Changing state done: " + args.Next);
            }
            catch (Exception ex)
            {
                _log.Fatal("Failed to change state from " + args.Previous + " to " + args.Next, ex);

                throw;
            }
        }

        private void InitializeState(AddinState state)
        {
            switch (state)
            {
                case AddinState.WindowsServiceNotRunning:
                    this.flowSharePoint.Controls.Add(new SettingsControls.ServiceNotRunning(this));

                    this.flowAbout.Controls.Add(new SettingsControls.AboutTelerik(this));
                    this.flowAbout.Controls.Add(new SettingsControls.About(this));
                    break;

                case AddinState.ConnectingToSharePoint:
                    this.flowSharePoint.Controls.Add(new SettingsControls.Connecting(this));

                    this.flowMaintaince.Controls.Add(new SettingsControls.ErrorReporting(this));

                    this.flowAbout.Controls.Add(new SettingsControls.UpdateStatus(this));
                    this.flowAbout.Controls.Add(new SettingsControls.AboutTelerik(this));
                    this.flowAbout.Controls.Add(new SettingsControls.About(this));
                    break;

                case AddinState.SharePointNotInstalled:
                    this.flowSharePoint.Controls.Add(new SettingsControls.SharePointNotInstalled(this));

                    this.flowMaintaince.Controls.Add(new SettingsControls.ErrorReporting(this));

                    this.flowAbout.Controls.Add(new SettingsControls.UpdateStatus(this));
                    this.flowAbout.Controls.Add(new SettingsControls.AboutTelerik(this));
                    this.flowAbout.Controls.Add(new SettingsControls.About(this));
                    break;

                case AddinState.SharePointNotUmbrella:
                    this.flowSharePoint.Controls.Add(new SettingsControls.SharePointNotUmbrella(this));

                    this.flowMaintaince.Controls.Add(new SettingsControls.ErrorReporting(this));

                    this.flowAbout.Controls.Add(new SettingsControls.UpdateStatus(this));
                    this.flowAbout.Controls.Add(new SettingsControls.AboutTelerik(this));
                    this.flowAbout.Controls.Add(new SettingsControls.About(this));
                    break;

                case AddinState.Ready:
                    this.flowSharePoint.Controls.Add(new SettingsControls.SharePointReady(this));

                    this.flowMaintaince.Controls.Add(new SettingsControls.ErrorReporting(this));

                    this.flowAbout.Controls.Add(new SettingsControls.UpdateStatus(this));
                    this.flowAbout.Controls.Add(new SettingsControls.AboutTelerik(this));
                    this.flowAbout.Controls.Add(new SettingsControls.About(this));
                    break;

                default:
                    _log.Error("state is not valid for console screen: " + state);
                    break;
            }
        }

        private void CleanupFlowLayoutPanel(FlowLayoutPanel panel)
        {
            if (panel == null)
                throw new ArgumentNullException("panel");

            foreach (SettingsControls.SettingsControlBase c in panel.Controls)
            {
                try
                {
                    c.Dispose();
                }
                catch (Exception ex)
                {
                    _log.Warn("Failed to dispose control", ex);
                }
            }

            panel.Controls.Clear();
        }

    }
}